﻿#pragma once
#ifndef WsService_hpp
#define WsService_hpp

//#define UWS_NO_ZLIB

#include<memory>
#include<string>
#include<cstdint>
#include<thread>
#include<iostream>
#include<functional>
#include"App.h"
#include"WsDispather.hpp"

namespace MMF
{

    template<typename UserDataT>
    class WsService
    {
        std::unique_ptr<uWS::App> mWsApp;                           ///< uWebsockets上下文
        std::string mRouter;                                        ///< ws的路由
        uint16_t mPort;                                             ///< 服务监听端口
        std::unique_ptr<std::thread> mRunThr;                       ///< 服务运行线程
        std::unique_ptr<WsDispather<UserDataT>> mDispathter;        ///< 消息分发器

    public:

        using Callback = std::function<void(uWS::WebSocket<false,true,UserDataT>* ws, MMFNetwork::MMFMessageHeader* pkg)>;

        WsService(const std::string& router, uint16_t port)
        {
            mRouter = router;
            mPort = port;

            mDispathter = std::make_unique<WsDispather<UserDataT>>([this](uWS::WebSocket<false,true,UserDataT>* ws, MMFNetwork::MMFMessageHeader* pkg){
                //这里处理没有注册回调函数的消息
                std::cout << "WsService unhandled mesaage for header:" << pkg->mName << std::endl;
            });
        }

        void RegisterClientOpenHanlder(const Callback&& handler)
        {
            mDispathter->RegisterClientOpenHanlder(std::move(handler));
        }

        void RegisterClientCloseHanlder(const Callback&& handler)
        {
            mDispathter->RegisterClientCloseHanlder(std::move(handler));
        }

        ~WsService()
        {
            //等待线程退出
            if (mRunThr->joinable())
                mRunThr->join();
        }

        bool Start()
        {
            //在异步线程启动这样不会卡死主线程
            mRunThr = std::make_unique<std::thread>([this](){
                
                    mWsApp = std::make_unique<uWS::App>();
                    mWsApp->ws<UserDataT>(mRouter, {

                    //设置一些协议的参数
                    .compression = uWS::CompressOptions(uWS::DEDICATED_COMPRESSOR_4KB | uWS::DEDICATED_DECOMPRESSOR),
                    .maxPayloadLength = 100 * 1024 * 1024,
                    .idleTimeout = 16,
                    .maxBackpressure = 100 * 1024 * 1024,
                    .closeOnBackpressureLimit = false,
                    .resetIdleTimeoutOnSend = false,
                    .sendPingsAutomatically = true,

                    //设置回调函数
                    .upgrade = nullptr,
                    .open = [this](uWS::WebSocket<false,true,UserDataT>* ws) {

                        //拼凑并模拟一个消息
                        char msgStr[] = "WsConnected";
                        char buff[sizeof(MMFNetwork::MMFMessageHeader) + sizeof(msgStr)];
                        MMFNetwork::MMFMessageHeader* header = (MMFNetwork::MMFMessageHeader*)buff;
                        header->mType = MMFNetwork::MMFMesaageType::Bin;
                        header->mDataBytes = sizeof(buff);
                        header->mNameBytes = sizeof(msgStr);
                        memcpy(header->mName, msgStr, sizeof(msgStr));

                        mDispathter->HandleMessage(ws, buff, header->mDataBytes);
                    },    
                    .message = [this](uWS::WebSocket<false,true,UserDataT>* ws, std::string_view message, uWS::OpCode opCode) {
                        
                        //派发消息
                        MMFNetwork::MMFMessageHeader* header = (MMFNetwork::MMFMessageHeader*)message.data();
                        mDispathter->HandleMessage(ws, (void*)message.data(), header->mDataBytes);
                    },
                    .dropped = [this](uWS::WebSocket<false,true,UserDataT>* /*ws*/, std::string_view /*message*/, uWS::OpCode /*opCode*/) {
                        //当数据丢弃的时候会走到这里

                    },
                    .drain = [](auto */*ws*/){},
                    .ping = [](auto */*ws*/, std::string_view) {},
                    .pong = [](auto */*ws*/, std::string_view) {},
                    .close = [this](uWS::WebSocket<false,true,UserDataT>* ws, int /*code*/, std::string_view /*message*/) {

                        //拼凑并模拟一个消息
                        char msgStr[] = "WsClose";
                        char buff[sizeof(MMFNetwork::MMFMessageHeader) + sizeof(msgStr)];
                        MMFNetwork::MMFMessageHeader* header = (MMFNetwork::MMFMessageHeader*)buff;
                        header->mType = MMFNetwork::MMFMesaageType::Bin;
                        header->mDataBytes = sizeof(buff);
                        header->mNameBytes = sizeof(msgStr);
                        memcpy(header->mName, msgStr, sizeof(msgStr));

                        mDispathter->HandleMessage(ws, buff, header->mDataBytes);
                    }
                });

                //监听
                mWsApp->listen("0.0.0.0", mPort, [this](auto* listenSocket) {
                    if (listenSocket) 
                        std::cout << "WS port " << mPort << std::endl;
                    else 
                        std::cout << "WS port Failed " <<  mPort << std::endl;
                });
    
                std::cout << "WsComtrol Start! Router " << mRouter << ", Port " << mPort << std::endl;
    
                mWsApp->run();
            });

            return true;
        }

        void Stop()
        {
            mWsApp->close();
        }

        WsDispather<UserDataT>& Dispathter()
        {
            return *mDispathter;
        }
    };

    
}


#endif